package com.ssl.rms.handler;

import com.ssl.rms.constants.SystemConstant;
import com.ssl.rms.exception.ApiResponse;
import com.ssl.rms.exception.BaseException;
import com.ssl.rms.exception.ResultFlagType;
import com.ssl.rms.utils.HttpUtil;
import com.ssl.rms.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.BindException;
import java.text.MessageFormat;

/**
 * 描述：统一异常处理
 *
 * @author shi_senlin
 * @create 2018/04/29 19:47
 */
public class UnifiedExceptionResolver implements HandlerExceptionResolver {
    private static final Logger logger = LoggerFactory.getLogger(UnifiedExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse
            httpServletResponse, Object o, Exception e) {
        if (null == e) {
            return null;
        }
        /** 打印堆栈信息 */
        String ip = StringUtils.getRemoteAddr(httpServletRequest);
        String url = httpServletRequest.getRequestURL().toString();
        String method = httpServletRequest.getMethod();
        logger.error(MessageFormat.format("出错请求信息：ip[{0}],url[{1}],method[{2}]]", ip, url, method), e);
        ModelAndView mv = null;
        int statusCode = 500;
        ApiResponse fail = null;
        if (e instanceof HttpRequestMethodNotSupportedException) {
            fail = ApiResponse.fail(ResultFlagType.HTTP_REQUEST_METHOD_NOT_SUPPORTED);
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            fail = ApiResponse.fail(ResultFlagType.PARAM_TYPE_MISMATCH);
        } else if (e instanceof HttpMediaTypeNotAcceptableException) {
            statusCode = HttpServletResponse.SC_NOT_ACCEPTABLE;
            fail = ApiResponse.fail(statusCode, "请求媒体类型不允许");
        } else if (e instanceof MissingServletRequestParameterException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            fail = ApiResponse.fail(statusCode, "参数缺失");
        } else if (e instanceof ServletRequestBindingException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            fail = ApiResponse.fail(statusCode, "参数绑定失败");
        } else if (e instanceof ConversionNotSupportedException) {
            statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
            fail = ApiResponse.fail(statusCode, "参数转换不支持");
        } else if (e instanceof TypeMismatchException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            fail = ApiResponse.fail(ResultFlagType.PARAM_TYPE_MISMATCH);
        } else if (e instanceof HttpMessageNotReadableException) {
            HttpMessageNotReadableException ex = (HttpMessageNotReadableException) e;
            fail = ApiResponse.fail(ResultFlagType.HTTP_MESSAGE_NOT_READABLE.getCode(), null == ex.getRootCause() ? e
                    .getMessage() : ex.getRootCause().getMessage());
        } else if (e instanceof HttpMessageNotWritableException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            fail = ApiResponse.fail(statusCode, "消息内容不可写");
        } else if (e instanceof MethodArgumentNotValidException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            BindingResult bindingResult = ex.getBindingResult();
            StringBuffer sb = new StringBuffer();

            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                sb.append(fieldError.getDefaultMessage()).append(SystemConstant.NEW_LINE_CHARS);
            }
            String errorMesssage = sb.toString();
            if (errorMesssage.length() > 0) {
                errorMesssage = errorMesssage.substring(0, errorMesssage.length() - SystemConstant.NEW_LINE_CHARS
                        .length());
            }
            fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID.getCode(), errorMesssage);
        } else if (e instanceof MissingServletRequestPartException) {
            statusCode = HttpServletResponse.SC_BAD_REQUEST;
            fail = ApiResponse.fail(statusCode, "上传文件丢失");
        } else if (e instanceof BindException) {
            fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID);
        } else if (e instanceof NoHandlerFoundException) {
            statusCode = HttpServletResponse.SC_NOT_FOUND;
            fail = ApiResponse.fail(statusCode, "响应处理器匹配失败");
        } else if (e instanceof BaseException) {
            BaseException ex = (BaseException) e;
            if (ResultFlagType.LOGIN_TIMEOUT.getCode().toString().equals(ex.getErrorCode())) {
                fail = ApiResponse.overdue(ex.getErrorCode(), ex.getErrorMsg());
            } else {
                fail = ApiResponse.fail(ex.getErrorCode(), ex.getErrorMsg());
            }
        } else if (e instanceof org.springframework.validation.BindException) {
            org.springframework.validation.BindException ex = (org.springframework.validation.BindException) e;
            BindingResult bindingResult = ex.getBindingResult();
            StringBuffer sb = new StringBuffer();

            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                sb.append(fieldError.getDefaultMessage()).append(SystemConstant.NEW_LINE_CHARS);
            }
            String errorMesssage = sb.toString();
            if (errorMesssage.length() > 0) {
                errorMesssage = errorMesssage.substring(0, errorMesssage.length() - SystemConstant.NEW_LINE_CHARS
                        .length());
            }
            fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID.getCode(), errorMesssage);
        } else if (e instanceof MultipartException) {
            fail = ApiResponse.fail(ResultFlagType.HTTP_UPLOAD_SIZE_EXCEEDED);
        } else if (e instanceof RuntimeException) {
            fail = ApiResponse.fail(ResultFlagType.HTTP_UNEXPECTED_SERVER_ERROR);
        } else {
            fail = ApiResponse.fail(ResultFlagType.FAIL);
        }
        try {
            if (HttpUtil.isAjax(httpServletRequest)) {
                mv = new ModelAndView(new JsonView());
            } else {
                mv = new ModelAndView(errorView);
            }
            mv.addObject(SystemConstant.ERROR_OBJECT, fail);
            return mv;
        } catch (Exception ex) {
            logger.debug("异常处理出错了.", ex);
        }
        return null;
    }

    /**
     * 错误视图
     */
    private String errorView;

    public String getErrorView() {
        return errorView;
    }

    public void setErrorView(String errorView) {
        this.errorView = errorView;
    }
}
